#include "GameInfo.h"
#include "GameException.h"

#include <string.h>

GameInfo::GameInfo(void)
{
	int count;

	this->_score[0] = 0;
	this->_score[1] = 0;

	this->_currentPlayer = CURRENTPLAYERWHITE;
	this->_map = new int*[LENGTHBOARD];
	for (count = 0; count < LENGTHBOARD; count++)
		this->_map[count] = new int[LENGTHBOARD],
                memset(this->_map[count], 0, sizeof(int) * LENGTHBOARD);
}

GameInfo::~GameInfo()
{
	int count;

	for (count = 0; count < LENGTHBOARD; count++)
		delete[] this->_map[count];
	delete[] this->_map;
}

GameInfo::GameInfo(GameInfo& info)
{
	int count;

	this->_map = new int*[LENGTHBOARD];
	for(count = 0; count < LENGTHBOARD; count++)
		this->_map[count] = new int[LENGTHBOARD], memcpy(this->_map[count], info.getMap()[count], LENGTHBOARD);
	this->_currentPlayer = info.getCurrentPlayer();
	this->_score[0] = this->getScore()[0];
	this->_score[1] = this->getScore()[1];
}

int**	GameInfo::getMap(void)
{
	return this->_map;
}

char	GameInfo::getCurrentPlayer(void)
{
	return this->_currentPlayer;
}

char*	GameInfo::getScore(void)
{
	return this->_score;
}

void	GameInfo::putPieceOnMap(coord_t& coord)
{
	int		count;
	int		stop = 0;

	this->_map[coord.y][coord.x] = initMask(coord.y, coord.x);
	for (count = 0; stop != 255 && count < LENGTHBOARD ; count++)
	{
		if (stop & 1)
		{
			if ((coord.y - count) >= 0 &&
				this->_map[coord.y - count][coord.x] != EMPTY)
			{
				if (isOpposite(this->_currentPlayer, 
								this->_map[coord.y - count][coord.x]) == false)
					this->_map[coord.y - count][coord.x] |= (this->_map[coord.y][coord.x] & TOTALH);
				else if (CHECKMASK(this->_map[coord.y - count][coord.x], TRH) != true)
					this->_map[coord.y - count][coord.x] |= TRH;
				else
					stop |= 1;
			}
			else
				stop |= 1;
		}

		if (stop & 2)
		{
			if ((coord.y + count) < LENGTHBOARD &&
				this->_map[coord.y + count][coord.x] != EMPTY)
			{
				if (isOpposite(this->_currentPlayer, 
								this->_map[coord.y + count][coord.x]) == false)
					this->_map[coord.y + count][coord.x] |= (this->_map[coord.y][coord.x] & TOTALH);
				else if (CHECKMASK(this->_map[coord.y + count][coord.x], TLH) != true)
					this->_map[coord.y + count][coord.x] |= TLH;
				else
					stop |= 2;
			}
			else
				stop |= 2;
		}

			if (stop & 4)
		{
			if ((coord.x - count) >= 0 &&
				this->_map[coord.y][coord.x - count] != EMPTY)
			{
				if (isOpposite(this->_currentPlayer, 
								this->_map[coord.y][coord.x - count]) == false)
					this->_map[coord.y][coord.x - count] |= (this->_map[coord.y][coord.x] & TOTALV);
				else if (CHECKMASK(this->_map[coord.y][coord.x - count], TRV) != true)
					this->_map[coord.y][coord.x - count] |= TRV;
				else
					stop |= 4;
			}
			else
				stop |= 4;
		}

		if (stop & 8)
		{
			if ((coord.x + count) < LENGTHBOARD &&
				this->_map[coord.y][coord.x + count] != EMPTY)
			{
				if (isOpposite(this->_currentPlayer, 
								this->_map[coord.y][coord.x + count]) == false)
					this->_map[coord.y][coord.x + count] |= (this->_map[coord.y][coord.x] & TOTALV);
				else if (CHECKMASK(this->_map[coord.y][coord.x + count], TLV) != true)
					this->_map[coord.y][coord.x + count] |= TLV;
				else
					stop |= 8;
			}
			else
				stop |= 8;
		}

		if (stop & 16)
		{

			if ((coord.y - count) >= 0 && (coord.x - count) >= 0 && 
				this->_map[coord.y - count][coord.x - count] != EMPTY)
			{
				if (isOpposite(this->_currentPlayer, 
							this->_map[coord.y - count][coord.x - count]) == false)
					this->_map[coord.y - count][coord.x - count] |= (this->_map[coord.y][coord.x] & TOTALDNS);
				else if (CHECKMASK(this->_map[coord.y - count][coord.x - count], TRDNS) != true)
					this->_map[coord.y - count][coord.x - count] |= TRDNS;
				else
					stop |= 16;
			}
			else
				stop |= 16;
		}

		if (stop & 32)
		{

			if ((coord.y + count) < LENGTHBOARD && (coord.x + count) < LENGTHBOARD && 
				this->_map[coord.y + count][coord.x + count] != EMPTY)
			{
				if (isOpposite(this->_currentPlayer, 
							this->_map[coord.y + count][coord.x + count]) == false)
					this->_map[coord.y + count][coord.x + count] |= (this->_map[coord.y][coord.x] & TOTALDNS);
				else if (CHECKMASK(this->_map[coord.y + count][coord.x + count], TLDNS) != true)
					this->_map[coord.y + count][coord.x + count] |= TLDNS;
				else
					stop |= 32;
			}
			else
				stop |= 32;
		}

		if (stop & 64)
		{

			if ((coord.y - count) >= 0 && (coord.x + count) < LENGTHBOARD && 
				this->_map[coord.y - count][coord.x + count] != EMPTY)
			{
				if (isOpposite(this->_currentPlayer, 
							this->_map[coord.y - count][coord.x + count]) == false)
					this->_map[coord.y - count][coord.x + count] |= (this->_map[coord.y][coord.x] & TOTALDSN);
				else if (CHECKMASK(this->_map[coord.y - count][coord.x + count], TLDSN) != true)
					this->_map[coord.y - count][coord.x + count] |= TLDSN;
				else
					stop |= 64;
			}
			else
				stop |= 64;
		}

		if (stop & 128)
		{

			if ((coord.y + count) < LENGTHBOARD && (coord.x - count) >= 0 && 
				this->_map[coord.y + count][coord.x - count] != EMPTY)
			{
				if (isOpposite(this->_currentPlayer, 
							this->_map[coord.y + count][coord.x - count]) == false)
					this->_map[coord.y + count][coord.x - count] |= (this->_map[coord.y][coord.x] & TOTALDSN);
				else if (CHECKMASK(this->_map[coord.y + count][coord.x - count], TRDSN) != true)
					this->_map[coord.y + count][coord.x - count] |= TRDSN;
				else
					stop |= 128;
			}
			else
				stop |= 128;
		}
	}
}

int	GameInfo::initMask(int y, int x)
{
	int mask = ADDCURRENTPLAYER(this->_currentPlayer); 
	int tmp;

	tmp = 0;
	if ((y - 1) >= 0 && this->_map[y - 1][x] > 0)
		if (isOpposite(this->_currentPlayer, this->_map[y - 1][x]) == false)
			mask |= (this->_map[y - 1][x] & TOTALH), tmp = NBH(this->_map[y - 1][x]);
		else
			mask |= TLH;
	if ((y + 1) < LENGTHBOARD && this->_map[y + 1][x] > 0)
		if (isOpposite(this->_currentPlayer, this->_map[y + 1][x]) == false)
			mask |= (this->_map[y + 1][x] & TOTALH) | MKH(tmp + NBH(this->_map[y + 1][x]));
		else
			mask |= TRH;
	
	tmp = 0;
	if ((x - 1) >= 0 && this->_map[y][x - 1] > 0)
		if (isOpposite(this->_currentPlayer, this->_map[y][x - 1]) == false)
			mask |= (this->_map[y][x - 1] & TOTALV), tmp = NBV(this->_map[y][x - 1]);
		else
			mask |= TLV;
	if ((x + 1) < LENGTHBOARD && this->_map[y][x + 1] > 0)
		if (isOpposite(this->_currentPlayer, this->_map[y][x + 1]) == false)
			mask |= (this->_map[y][x + 1] & TOTALV) | MKV(tmp + NBV(this->_map[y][x + 1]));
		else
			mask |= TRV;
	
	tmp = 0;
	if ((x - 1) >= 0 && (y - 1)  >= 0 && this->_map[y - 1][x - 1] > 0)
		if (isOpposite(this->_currentPlayer, this->_map[y - 1][x - 1]) == false)
			mask |= (this->_map[y - 1][x - 1] & TOTALDNS), tmp = NBDNS(this->_map[y - 1][x - 1]);
		else
			mask |= TLDNS;
	if ((x + 1) < LENGTHBOARD && (y + 1) < LENGTHBOARD && this->_map[y + 1][x + 1] > 0)
		if (isOpposite(this->_currentPlayer, this->_map[y + 1][x + 1]) == false)
			mask |= (this->_map[y + 1][x + 1] & TOTALDNS) | MKDNS(tmp + NBDNS(this->_map[y + 1][x + 1]));
		else
			mask |= TRDNS;
	
	tmp = 0;
	if ((x - 1) >= 0 && (y + 1) < LENGTHBOARD && this->_map[y + 1][x - 1] > 0)
		if (isOpposite(this->_currentPlayer, this->_map[y + 1][x - 1]) == false)
			mask |= (this->_map[y + 1][x - 1] & TOTALDSN), tmp = NBDSN(this->_map[y + 1][x - 1]);
		else
			mask |= TLDSN;
	if ((x + 1) < LENGTHBOARD && (y - 1) >= 0 && this->_map[y - 1][x + 1] > 0)
		if (isOpposite(this->_currentPlayer, this->_map[y - 1][x + 1]) == false)
			mask |= (this->_map[y - 1][x + 1] & TOTALDSN) | MKDSN(tmp + NBDNS(this->_map[y - 1][x + 1]));
		else
			mask |= TRDSN;

	return mask;
}

void	GameInfo::incScore(char c)
{
	this->_score[this->_currentPlayer] += (2 * c);
	if (this->_score[this->_currentPlayer] >= 10)
		throw new GameExceptionWinByScore();
}

void	GameInfo::endRoundOfPlayer(void)
{
	this->_currentPlayer += SWITCHPLAYER(this->_currentPlayer);
}

void	GameInfo::takeOffPieceOnBoard(int y, int x, Way way)
{
	_map[y][x] = 0;
	INCCOORD(x, y, way);
	_map[y][x] = 0;
	INCCOORD(x, y, way);

	switch(way)
	{
	case NORTH:
		_map[y][x] -= TRH;
		_map[y + 3][x] -= TLH;
		break;
	case SOUTH:
		_map[y][x] -= TLH;
		_map[y - 3][x] -= TRH;
		break;
	case EAST:
		_map[y][x] -= TLH;
		_map[y][x - 3] -= TRH;
		break;
	case WEST:
		_map[y][x] -= TRH;
		_map[y][x + 3] -= TLH;
		break;
	case NORTHWEST:
		_map[y][x] -= TRDNS;
		_map[y + 3][x + 3] -= TLDNS;
		break;
	case NORTHEAST:
		_map[y][x] -= TLDSN;
		_map[y + 3][x - 3] -= TRDSN;
		break;
	case SOUTHEAST:
		_map[y][x] -= TLDNS;
		_map[y - 3][x - 3] -= TRDNS;
		break;
	case SOUTHWEST:
		_map[y][x] -= TRDSN;
		_map[y - 3][x + 3] -= TLDSN;
	default:
		break;
	}
}
